;;; functionality relevant for creating models
(defpackage model
  (:use :cl)
  (:nicknames :m)
  (:export :dump-screen
           :execute
           :main-screen
           :list-sessions
           :list-options
           :start-session
           :now-function
           :suppress-drawing-p
           :add-timer-function
           :cancel-timer-function
           :cancel-all-timers-function
           :execute-timer
           :*symbol-package*
           :model-mode
           :human-mode))

(defpackage :model-server
  (:use :cl)
  (:export :start
           :execute-action
           :dump-screen
           :main-screen
           :list-sessions
           :list-options
           :start-session))

(in-package :model)

(defvar *symbol-package* nil
  "Set this to the package you want all symbols to be put in. Otherwise defaults to *package*.")

;; (defun assert-model-mode ()
;;   (assert (eq gwee::*event-handler-function* #'gwee::model-event-handler) ()
;;           "You must be in model mode to run this function."))

(defun clean-up-symbols (sexp)
  (cond
    ((keywordp sexp)
     sexp)
    ((and (symbolp sexp)
          (eq (symbol-package sexp) (find-package :cl)))
     sexp)
    ((symbolp sexp)
     (let ((sym (intern (symbol-name sexp) (or *symbol-package* *package*))))
       sym))
    ((listp sexp)
     (mapcar 'clean-up-symbols sexp))
    (t
     sexp)))

(defmacro define-command (name args &optional (call `(quote ,(list (find-symbol (symbol-name name) :model-server)))))
  `(defun ,name ,args
     ;; (assert-model-mode)
     ;; make all the symbols appear to be in the current package
     (values-list (mapcar 'clean-up-symbols
                          (multiple-value-list (gwee::remote-eval ,call))))))

(define-command dump-screen ())
(define-command execute (action-class &rest args &key &allow-other-keys)
  `(model-server:execute-action ',action-class ,@(mapcar (lambda (a) (list 'quote a)) args)))
(define-command main-screen ())
(define-command list-sessions (id)
  `(model-server:list-sessions ,id))
(define-command list-options ())
(define-command start-session (id session &rest options &key &allow-other-keys)
 `(model-server:start-session ,id ,session ,@options))

(defun now-function ()
  (symbol-function 'gwee:now))

(defun (setf now-function) (fn)
  (setf (symbol-function 'gwee:now) fn))

(defun suppress-drawing-p ()
  ;; (assert-model-mode)
  (gwee::remote-eval '(gwee::suppress-drawing-p gwee::*top-view*)))

(defun (setf suppress-drawing-p) (val)
  ;; (assert-model-mode)
  (gwee::remote-eval `(setf (gwee::suppress-drawing-p gwee::*top-view*) ,val)))

(defun (setf add-timer-function) (fn)
  (setf gwee::*add-timer-function* fn))

(defun (setf cancel-timer-function) (fn)
  (setf (symbol-function 'gwee::cancel-timer) fn))

(defun (setf cancel-all-timers-function) (fn)
  (setf (symbol-function 'gwee::cancel-all-timers) fn))

(defun execute-timer (timer)
  ;; (assert-model-mode)
  (gwee::remote-eval `(apply (gwee::timer-function ,timer)
                             (gwee::timer-args ,timer))))

(defun model-mode ()
  (setf gwee::*event-handler-function* #'gwee::model-event-handler))

(defun human-mode ()
  (setf gwee::*event-handler-function* #'gwee::human-event-handler))
